
#include "config/config.h"
#include "mqtt/mqtt_client.h"
#include "log/syslog.h"
#include <iostream>
#include <string>
using namespace std;
using namespace equip_system;

extern system_log::CSysLog syslog;

//
#define TAG "MqttClient"

// // 类型映射：将void*转换为mqtt::client*
// inline client *get_client(void *handle)
// {
//     return static_cast<client *>(handle);
// }

MqttClient::MqttClient()
    : client_handle_(nullptr), connected_(false)
{
    // 初始化客户端句柄
    MQTTClient_create(&client_handle_, "", config_.client_id.c_str(), MQTTCLIENT_PERSISTENCE_NONE, NULL);
}

MqttClient::~MqttClient()
{
    disconnect();                        // 析构时确保断开连接
    MQTTClient_destroy(&client_handle_); // 销毁客户端
}

bool MqttClient::connect(const MqttConfig &config)
{
    // 若已连接，先断开
    if (connected_)
    {
        disconnect();
    }

    // 保存配置
    config_ = config;

    try
    {
        // 构建服务器URI（格式：tcp://ip:port）
        string server_uri = config.protocol + config.broker_ip + ":" + to_string(config.broker_port);
        
        int rc = MQTTClient_create(&client_handle_, server_uri.c_str(), config.client_id.c_str(), 0, NULL);
        if (rc != MQTTCLIENT_SUCCESS)
        {
            ES_LOG(TAG, LEVEL_ERROR, "MQTT create failed: %d", rc);
            if (connect_callback_)
                connect_callback_(false);
            return false;
        }


        // 初始化连接选项（C库结构体）
        MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
        conn_opts.keepAliveInterval = config.keep_alive; // 心跳间隔
        conn_opts.connectTimeout = config.timeout;       // 超时时间
        conn_opts.cleansession = 1;                      // 清理会话

        // 设置用户名密码（如果有）
        if (!config.username.empty())
        {
            conn_opts.username = config.username.c_str();
            conn_opts.password = config.password.c_str();
        }

        // 连接服务器
        ES_LOG(TAG, LEVEL_INFO, "Connecting to MQTT broker: %s ......" , server_uri.c_str()); // 注意转换为const char*
        rc = MQTTClient_connect(client_handle_, &conn_opts);
        if (rc == MQTTCLIENT_SUCCESS)
        {
            connected_ = true;
            ES_LOG(TAG, LEVEL_INFO, "MQTT connected successfully");
            if (connect_callback_)
                connect_callback_(true);
            return true;
        }
        else
        {
            switch(rc)
            {
                case 1:ES_LOG(TAG, LEVEL_ERROR, "MQTT connect failed: %d (Connection refused: Unacceptable protocol version)", rc);;break;
                case 2:ES_LOG(TAG, LEVEL_ERROR, "MQTT connect failed: %d (Connection refused: Identifier rejected)", rc);;break;
                case 3:ES_LOG(TAG, LEVEL_ERROR, "MQTT connect failed: %d (Connection refused: Server unavailable)", rc);;break;
                case 4:ES_LOG(TAG, LEVEL_ERROR, "MQTT connect failed: %d (Connection refused: Bad user name or password)", rc);;break;
                case 5:ES_LOG(TAG, LEVEL_ERROR, "MQTT connect failed: %d (Connection refused: Not authorized)", rc);;break;
                case 6:ES_LOG(TAG, LEVEL_ERROR, "MQTT connect failed: %d (Reserved for future use)", rc);;break;
            }
            
            if (connect_callback_)
                connect_callback_(false);
            return false;
        }
    }
    catch (const exception &e)
    {
        // 捕获异常（如网络错误、端口未开放等）
        ES_LOG(TAG, LEVEL_ERROR, "MQTT init failed: %s" , e.what());
        if (connect_callback_)
        {
            connect_callback_(false);
        }
        return false;
    }

    return true; //
}

bool MqttClient::publish(const std::string &topic, const std::string &payload, int qos, bool retain)
{
    // 检查连接状态
    if (!connected_)
    {
        ES_LOG(TAG, LEVEL_WARNING, "Publish failed: not connected");
        return false;
    }

    try
    {
        // 构建消息（C库结构体）
        MQTTClient_message msg = MQTTClient_message_initializer;
        msg.payload = (void *)payload.c_str();
        msg.payloadlen = payload.length();
        msg.qos = qos;
        msg.retained = retain ? 1 : 0;

        // 发布消息
        MQTTClient_deliveryToken token;
        int rc = MQTTClient_publishMessage(client_handle_, topic.c_str(), &msg, &token);
        if (rc != MQTTCLIENT_SUCCESS)
        {
            ES_LOG(TAG, LEVEL_ERROR, "Publish failed: %d" ,rc);
            connected_ = false; // 发布失败视为断开
            if (connect_callback_)
                connect_callback_(false);
            return false;
        }

        // 等待发布确认（超时3秒）
        rc = MQTTClient_waitForCompletion(client_handle_, token, 3000); // 3000毫秒超时
        if (rc == MQTTCLIENT_SUCCESS)
        {
            ES_LOG(TAG, LEVEL_INFO, "Published to %s: %s" , topic.c_str() , payload.c_str());
            return true;
        }
        else
        {
            ES_LOG(TAG, LEVEL_ERROR, "Publish timeout: %d" , rc);
            return false;
        }
    }
    catch (const exception &e)
    {
        ES_LOG(TAG, LEVEL_ERROR, "Publish exception: %s" , e.what());
        return false;
    }

    // if (!client)
    // {
    //     // std::cerr << "MQTT not connected, publishing failed!" << std::endl;
    //     char _infor[256] = {"MQTT not connected, publishing failed!"};
    //     ES_LOG(TAG, LEVEL_ERROR, _infor);
    //     // syslog.print(_infor);
    //     return false;
    // }
    // // std::cout << "Post to MQTT Subject[" << topic << "]：" << message << std::endl;
    // std::string _infor("Post to MQTT Subject[");
    // _infor.append(topic);
    // _infor.append("]：");
    // _infor.append(message);
    // ES_LOG(TAG, LEVEL_INFO, _infor.c_str());
    // // syslog.print(_infor);

    // // ... 发布逻辑 ...
    // int ret = mqtt_publish(mqtt_handle, topic.c_str(), message.length(), message.c_str(), 0, 0);

    // if (ret != 0)
    // {
    //     client = nullptr; // 发布失败时标记为断开
    //     return false;
    // }

    return true;
}

void MqttClient::disconnect()
{
    if (connected_) {
        MQTTClient_disconnect(client_handle_, 1000);  // 1秒内断开
        connected_ = false;
        ES_LOG(TAG, LEVEL_INFO, "MQTT disconnected");
        if (connect_callback_) connect_callback_(false);
    }
}
